

import { _path, _g, _text } from "./svg.js"
import { split } from "../math/array.js"
import { _rotate2, _centre, isQueue, isMatrix, _dis, _mid } from "../math/index.js"
import { _mirror } from '../math/mirror.js'
import { linkPoints, linkCrossPoints } from '../math/points/linkPoints.js'
//  参数名参考webgl.type
const PATH_MODE = {
    POINTS: 'POINTS',
    LINES: 'LINES',
    LINE_STRIP: 'LINE_STRIP',
    LINE_LOOP: 'LINE_LOOP',
    LINE_FAN: 'LINE_FAN',
    // POLYGON: 'POLYGON',
    TRIANGLES: 'TRIANGLES',
    TRIANGLE_STRIP: 'TRIANGLE_STRIP',
    TRIANGLE_STRIP_LOOP: 'TRIANGLE_STRIP_LOOP',
    TRIANGLE_FAN: 'TRIANGLE_FAN',

    SQUARES: 'SQUARES',
    SQUARE_STRIP: 'SQUARE_STRIP',
    SQUARE_STRIP_LOOP: 'SQUARE_STRIP_LOOP',
    RAY: 'RAY',
    RAY_FAN: 'RAY_FAN',
    LINK: 'LINK'

}
export const pathModeTypes = Object.keys(PATH_MODE)
export const curveTypes = ['none', 'bezier', 'sawtooth',
    'semicircle', 'semicircle2', 'circle', 'diamond', 'cross',
    'triangle', 'triangle2', 'rightAngle', 'leftAngle', 'centripetal']

// M = moveto
// L = lineto
// H = horizontal lineto
// V = vertical lineto
// C = curveto
// S = smooth curveto
// Q = quadratic Bézier curve
// T = smooth quadratic Bézier curveto
// A = elliptical Arc
// Z = closepath
const pathCommandMap = {
    7: 'A',
    6: 'C',
    4: 'Q',
    2: 'L'
}
const _linkTo = (p) => {
    if (p.length === 0) {
        return ""
    }
    else if (isQueue(p)) {
        return _linkTo(p[0]) + (p.length > 0 ? _linkTo(p.slice(1)) : '')
    }
    return ` ${pathCommandMap[p.length]}${p.join(" ")}`
}
const _moveTo = (p) => {
    return `M${p.join(" ")}`
}
// 折线转曲线 
const polylineToBezier = (points) => {
    let len = points.length
    if (len === 2) {
        let [p1, p2] = points
        let p = [...p1, ...p2]
        return _linkTo(p)
    }
    else if (len >= 3) {
        let [p1, p2, p3, ...rest] = points
        let p = [...p1, ...p2, ...p3]
        return _linkTo(p) + polylineToBezier(rest)
    }
    return ""
}

// 曲线
const _bezier = (points, o) => {
    return points.map(t => {
        let [c1, c2] = _rotate2([o, t], 90)
        let stack = []
        stack.push(_moveTo(o))
        stack.push(_linkTo([...c1, ...c2, ...t]))
        return stack.join(" ")
    }).join(" ")
}
// 锯齿
const _sawtooth = (points, o) => {
    return points.map(t => {
        let [c1, c2] = _rotate2([o, t], 90)
        let stack = []
        stack.push(_moveTo(o))
        stack.push(_linkTo([c1, c2, t]))
        return stack.join(" ")
    }).join(" ")
}
// 圆形
const _circles = (points, o) => {
    return points.map((t, i) => {
        let o2 = _centre([o, t])
        let r = _dis(t, o) / 2
        return _circle({
            o: o2,
            r
        })
    }).join(" ")
}

// 半圆
const _semicircle = (points, o, options = {}) => {
    let { sweepFlag = false,
        radiusRatio = 1,
        xAxisRotation = 0,
        largeArcFlag = false } = options
    return points.map((t, i) => {
        let r = _dis(t, o) / 2
        let stack = []
        stack.push(_moveTo(o))
        stack.push(_linkTo([r, r, xAxisRotation, largeArcFlag ? 1 : 0, sweepFlag ? 1 : 0, ...t]))
        return stack.join(" ")

    }).join(" ")
}

// 向心弧线
const _centripetal = (points, loop = false) => {
    let o = _centre(points)
    let len = points.length

    return points.map((t, i) => {
        let next
        if (loop) {
            next = points[i === len - 1 ? 0 : (i + 1)]
        } else {
            next = points[i + 1]
        }
        if (next) {
            let stack = []
            stack.push(_moveTo(t))
            stack.push(_linkTo([...o, ...next]))
            return stack.join(" ")
        }
        return ""
    }).join(" ")
}

// 菱形
const _diamond = (points, o) => {
    return points.map(t => {
        let [c1, c2] = _rotate2([o, t], 90)
        let stack = []
        stack.push(_moveTo(o))
        stack.push(_linkTo([c1, t, c2, o]))
        return stack.join(" ")
    }).join(" ")
}
// 十字
const _cross = (points, o) => {
    return points.map(t => {
        let [c1, c2] = _rotate2([o, t], 90)
        let stack = []
        stack.push(_moveTo(c1))
        stack.push(_linkTo(c2))
        stack.push(_moveTo(o))
        stack.push(_linkTo(t))

        return stack.join(" ")
    }).join(" ")
}
// 三角形
const _triangle = (points, o) => {
    return points.map(t => {
        let [c1, c2] = _rotate2([o, t], 90)
        let stack = []
        stack.push(_moveTo(o))
        stack.push(_linkTo([c1, t, o]))
        return stack.join(" ")
    }).join(" ")
}

const _triangle2 = (points, o) => {
    return points.map(t => {
        let [c1, c2] = _rotate2([o, t], 90)
        let stack = []
        stack.push(_moveTo(o))
        stack.push(_linkTo([c2, t, o]))
        return stack.join(" ")
    }).join(" ")
}

// 直角拐线
const _rightAngle = (points, o) => {
    return points.map(t => {
        let [c1, c2] = _rotate2([o, t], 90)
        let stack = []
        stack.push(_moveTo(o))
        stack.push(_linkTo([c1, t]))
        return stack.join(" ")
    }).join(" ")
}

const _leftAngle = (points, o) => {
    return points.map(t => {
        let [c1, c2] = _rotate2([o, t], 90)
        let stack = []
        stack.push(_moveTo(o))
        stack.push(_linkTo([c2, t]))
        return stack.join(" ")
    }).join(" ")
}

//曲线
const _curve = (points, o, type) => {
    switch (type) {
        case 'bezier':
            return _bezier(points, o)
        case 'sawtooth':
            return _sawtooth(points, o)
        case 'circle':
            return _circles(points, o)
        case 'semicircle':
            return _semicircle(points, o)
        case 'semicircle2':
            return _semicircle(points, o, { sweepFlag: true })
        case 'diamond':
            return _diamond(points, o)
        case 'cross':
            return _cross(points, o)
        case 'triangle':
            return _triangle(points, o)
        case 'triangle2':
            return _triangle2(points, o)
        case 'rightAngle':
            return _rightAngle(points, o)
        case 'leftAngle':
            return _leftAngle(points, o)
        case 'centripetal':
            return _centripetal(points, o)
        default:
            return _bezier(points, o)
    }
}

// 判断曲线
const isCurve = (curve) => {
    return curve && curve !== 'none'
}
// 线段
const _lines = (points, curve) => {
    if (isCurve(curve)) {
        let matrix = split(points, 2)
        return matrix.map(ps => {
            return _curve(ps, ps[0], curve)
        }).join(" ")

    } else {
        return points.map(((t, i) => {
            let val = t.join(" ")
            return i % 2 === 0 ? `M${val}` : `L${val}`
        })).join(" ")

    }
}
// 中心射线
const _ray = (points, curve) => {
    let o = _centre(points)
    if (isCurve(curve)) {
        return _curve(points, o, curve)

    } else {
        return points.map((t) => {
            return [_moveTo(o), _linkTo(t)].join(" ")
        }).join(" ")
    }
}


// 连线 polyline
const _polyline = (points, curve) => {
    if (isCurve(curve)) {

        if (curve === 'centripetal') {
            return _centripetal(points)
        }
        let len = points.length
        return points.map((t, i) => {
            if (i < len - 1) {
                let next = points[i + 1]
                return _curve([t, next], t, curve)
            }
            return ""
        }).join(" ")

    } else {
        return points.map(((t, i) => {
            let val = t.join(" ")
            return i === 0 ? `M${val}` : `L${val}`
        })).join(" ")
    }
}


// LINE_LOOP
const _lineLoop = (points, curve) => {
    if (isCurve(curve)) {
        if (curve === 'centripetal') {
            return _centripetal(points, true)
        }
        let len = points.length
        return points.map((t, i) => {
            let next = points[(i < len - 1) ? i + 1 : 0]
            return _curve([t, next], t, curve)
        }).join(" ")

    }
    else {
        return _polyline(points) + 'z'
    }
}

const _rayFan = (points, curve) => {
    return _ray(points, curve) + _lineLoop(points)
}

// 多边形
const _polygons = (points, n, curve) => {
    let matrix = split(points, n)
    if (isCurve(curve)) {
        if (curve === 'bezier') {
            return matrix.map(ps => {
                let [p, ...rest] = ps
                let stack = []
                stack.push(_moveTo(p))
                stack.push(polylineToBezier(rest))
                stack.push(_linkTo(p))
                return stack.join(" ")
            }).join(" ")
        } else {

            return matrix.map(ps => {
                let p = ps[0]
                let stack = []
                stack.push(_moveTo(p))
                stack.push(_polyline(ps, curve))
                stack.push(_linkTo(p))
                return stack.join(" ")
            }).join(" ")
        }

    } else {
        return matrix.map(ps => {
            let len = ps.length
            return ps.map((t, i) => {
                let val = t.join(" ")
                return i % n === 0 ? `M${val}` : (i % n === len - 1) ? `L${val} L${ps[0].join(" ")}` : `L${val}`
            }).join(" ")
        }).join(" ")
    }
}
// 三角形
const _triangles = (points, curve) => {
    return _polygons(points, 3, curve)
}


// 四边形
const _squares = (points, curve) => {
    return _polygons(points, 4, curve)
}

// 扇线
const _lineFan = (points, curve) => {
    let [p, ...rest] = points
    if (isCurve(curve)) {
        // 曲线
        return _curve(rest, p, curve)
    } else {
        return rest.map(t => {
            let val = t.join(" ")
            return `M${p.join(" ")} L${val}`
        })
    }
}
// 扇形
const _fan = (points, curve) => {
    let o = points[0]
    let len = points.length
    if (len <= 2) return ""
    if (isCurve(curve)) {
        // 曲线
        return points.slice(0, len - 1).map((t, i) => {
            let stack = []
            let next = points[i + 1]
            stack.push(_curve([t, next], t, curve))
            stack.push(_linkTo(o))
            return stack.join(" ")
        }).join(" ")
    } else {
        return points.slice(1, len - 1).map((t, i) => {
            let val = t.join(" ")
            let next = points[i + 2].join(" ")
            return `M${o.join(" ")} L${val} L${next}`
        }).join(" ") + 'z'
    }
}



// 扇形：独立三角
// const _fan2 = (points) => {
//     let p = points[0].join(" ")
//     let len = points.length
//     if (len <= 2) return ""
//     return points.slice(1, len - 2).map((t, i) => {
//         let val = t.join(" ")
//         let next = points[i + 1].join(" ")

//         return `M${p} L${val} L${next} L${p}`
//     })
// }
// 带状
const _strip = (points, n, curve) => {
    if (isCurve(curve)) {
        return points.map((t, i) => {
            let stack = []
            stack.push(_moveTo(t))
            let rest = points.slice(i + 1, i + n)
            if (curve === 'bezier') {
                stack.push(polylineToBezier(rest))
            } else {
                stack.push(_polyline(rest, curve))
            }
            stack.push(_linkTo(t))
            return stack.join(" ")
        }).join(" ")
    } else {
        let len = points.length
        return points.slice(0, len - n + 1).map((t, i) => {
            let first = t.join(" ")
            let stack = [`M${first}`]
            for (let j = 1; j < n; j++) {
                let p = points[i + j]
                stack.push(_linkTo(p))
            }
            stack.push(`L${first}`)
            return stack.join(" ")
        }).join(" ")
    }
}
// 带状循环
const _stripLoop = (points, n, curve) => {
    let len = points.length
    if (isCurve(curve)) {

        return points.map((t, i) => {
            let stack = []
            stack.push(_moveTo(t))
            let start = (i + 1 >= len) ? (i + 1 - len) : (i + 1)
            let end = (i + n >= len) ? (i + n - len) : (i + n)

            let rest = end > start ? points.slice(start, end) : [...points.slice(start), ...points.slice(0, end)]
            if (curve === "bezier") {
                stack.push(polylineToBezier(rest))
            } else {
                stack.push(_polyline(rest, curve))
            }
            stack.push(_linkTo(t))
            return stack.join(" ")
        }).join(" ")


    } else {
        return points.map((t, i) => {
            let first = t.join(" ")
            let stack = [`M${first}`]
            for (let j = 1; j < n; j++) {
                let index = (i > len - j - 1) ? (i + j - len) : (i + j)
                let p = points[index]
                stack.push(_linkTo(p))
            }
            stack.push(`L${first}`)
            return stack.join(" ")
        })

    }

}
// 三角带
const _triangleStrip = (points, curve) => {
    return _strip(points, 3, curve)
}
// 四边带
const _squareStrip = (points, curve) => {
    return _strip(points, 4, curve)
}
// 循环三角带
const _triangleStripLoop = (points, curve) => {
    return _stripLoop(points, 3, curve)
}

// 循环四边形带
const _squareStripLoop = (points, curve) => {
    return _stripLoop(points, 4, curve)
}

const _circle = ({
    o, r
}) => {
    let [cx, cy] = o

    //非数值单位计算，如当宽度像100%则移除 
    if (isNaN(cx - cy)) return;
    var path = 'M' + (cx - r) + ' ' + cy + 'a' + r + ' ' + r + ' 0 1 0 ' + 2 * r + ' 0' + 'a' + r + ' ' + r + ' 0 1 0 ' + (-2 * r) + ' 0' + 'z';
    return path;
}
// 点
const _points = (points) => {
    return points.map(t => {
        return _circle({ o: t, r: 3 })
    }).join(" ")
}

// 标注
const _labels = ({ points = [], render }, opitons = {}, props = {}) => {

    return points.map((t, index) => {
        let [x, y] = t
        return _text({
            shape: 'text',
            x, y,
            text: render ? render(index) : index
        }, {
            name: 'text',
            'font-size': 12,
            'text-anchor': 'middle',
            'dominant-baseline': 'middle',
            ...props,
            ...opitons.props
        })
    })
}

// 连线  options, props
export const _link = (points, curve) => {
    if (points.length > 50) {
        alert('截取了50个节点，link')
        points = points.slice(0, 50)
    }
    let lps = linkPoints(points)
    return _polyline(lps, curve)
}

// 外圈顶点
const _borderPoints = (matrix, shape) => {
    return matrix[matrix.length - 1]
    // switch (shape) {
    //     case 'rayShape':
    //         return matrix.map(t => t[t.length - 1])

    //     default:
    //         return matrix[matrix.length - 1]
    // }
}
// 镜像点
const _mirrorPoint = (point, index, mirrorPoints) => {
    return mirrorPoints ? mirrorPoints[index % mirrorPoints.length] : point
}
export const _path2 = (options, props) => {
    let { shape, points, mode, curve, mirror, mirrorPoints, vertex, centre, excircle, incircle, labels, linkCross } = options

    if (isMatrix(points)) {
        let mirrorPoints = _borderPoints(points, shape)
        let arr = points.map((t, i) => {
            return _path2({
                ...options,
                points: t,
                mirrorPoints
            }, props)
        })
        return _g(arr)
    }

    let path = ""
    switch (mode) {
        case PATH_MODE.POINTS:
            path = _points(points)
            break
        case PATH_MODE.LINES:
            path = _lines(points, curve)
            break;
        case PATH_MODE.LINE_STRIP:
            path = _polyline(points, curve)
            break;
        case PATH_MODE.LINE_LOOP:
            // case PATH_MODE.POLYGON:
            path = _lineLoop(points, curve)
            break;
        case PATH_MODE.TRIANGLES:
            path = _triangles(points, curve)
            // return _triangles(points)
            break;
        case PATH_MODE.TRIANGLE_FAN:
            path = _fan(points, curve)
            break;
        case PATH_MODE.LINE_FAN:
            path = _lineFan(points, curve)
            break;
        case PATH_MODE.TRIANGLE_STRIP:
            path = _triangleStrip(points, curve)
            break;
        case PATH_MODE.TRIANGLE_STRIP_LOOP:
            path = _triangleStripLoop(points, curve)
            break;
        case PATH_MODE.SQUARES:
            path = _squares(points, curve)
            break;
        case PATH_MODE.SQUARE_STRIP:
            path = _squareStrip(points, curve)
            break;
        case PATH_MODE.SQUARE_STRIP_LOOP:
            path = _squareStripLoop(points, curve)
            break;
        case PATH_MODE.RAY:
            path = _ray(points, curve)
            break;
        case PATH_MODE.RAY_FAN:
            path = _rayFan(points, curve)
            break;
        case PATH_MODE.LINK:
            path = _link(points, curve)
            break;
        default:
            path = _lineLoop(points, curve)

    }
    let gs = []
    gs.push(_path(path, {
        stroke: 'red',
        fill: 'none',
        ...props
    }))
    // 顶点
    if (vertex) {
        gs.push(_path(_points(points), {
            ...props,
            fill: 'red',
            storke: 'none'
        }))
    }
    let o = _centre(points)
    // 中点
    if (centre) {
        gs.push(_path(_points([o]), {
            ...props,
            fill: 'red',
            storke: 'none'
        }))
    }
    // 外切圆
    if (excircle) {
        let r = _dis(o, points[0])
        let circle = _circle({ o, r })
        gs.push(_path(circle, props))
    }
    // 内切圆
    if (incircle) {
        let r = _dis(o, _mid.apply(null, points.slice(0, 2)))
        let circle = _circle({ o, r })
        gs.push(_path(circle, props))
    }
    // 标注
    if (labels) {
        gs.push(_labels({ points }, labels, {
            ...props,
            fill: 'none',
            stroke: 'blue'
        }))
    }
    // 连线交叉点
    if (linkCross) {
        if (points.length > 50) {
            alert('截取了50个节点，linkCross')
            points = points.slice(0, 50)
        }

        let lcps = linkCrossPoints(points)
        gs.push(_path(_points(lcps), {
            ...props,
            fill: 'red',
            storke: 'none'
        }))

    }

    // 镜像
    if (mirror && mirror !== 'none') {
        gs.push(..._mirrorPath({
            points, mode, curve, mirror, mirrorPoints,
            vertex, centre, excircle, incircle, labels, linkCross
        }, props))
    }
    return _g(gs)

}


// 镜像
const _mirrorPath = (options, props) => {
    let { shape, points, mirror, mirrorPoints } = options
    let fn = (ps) => {
        return _path2({
            ...options,
            points: ps,
            mirror: null
        }, props)
    }
    if (isMatrix(points)) {
        let mirrorPoints = _borderPoints(points, shape)
        return points.map((t, i) => {
            return _g(_mirrorPath({
                ...options,
                points: t,
                mirrorPoints
            }, props))
        })
    }

    switch (mirror) {
        case 'vertex':
            return points.map((t, i) => {
                let mp = _mirrorPoint(t, i, mirrorPoints)
                let ps = _mirror(points, mp)
                return fn(ps)
            })

        case 'edge': {
            let ms = _mid(points)
            let mms = mirrorPoints ? _mid(mirrorPoints) : null
            return ms.map((t, i) => {
                let mp = _mirrorPoint(t, i, mms)
                let ps = _mirror(points, mp)
                return fn(ps)
            })
        }

        case 'edgeMid': {
            let ms = _mid(points)
            let mms = mirrorPoints ? _mid(mirrorPoints) : null
            return ms.map((t, i) => {
                let mp = _mirrorPoint(t, i, mms)
                let ps = _mirror(ms, mp)
                return fn(ps)
            })
        }
        case 'radiusMid': {
            let o = _centre(points)
            return points.map((t, i) => {
                let mp = _mirrorPoint(t, i, mirrorPoints)
                let rm = _mid(mp, o)
                let ps = _mirror(points, rm)
                return fn(ps)
            })

        }

    }
}

export const mirrorTypes = ['none', 'vertex', 'edge', 'edgeMid', 'radiusMid']

